package netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;

import static io.netty.buffer.ByteBufUtil.appendPrettyHexDump;
import static io.netty.util.internal.StringUtil.NEWLINE;

public class ByteBufDemo {
    public static void main(String[] args) {
        // readByteBufDemo();
        // sliceDemo();
        //compositeByteBufDemo();
        unpooledDemo();
    }

    public static void readByteBufDemo() {
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
        // 写入
        buffer.writeBytes(new byte[]{1, 2, 3, 4});
        buffer.writeInt(1);
        log(buffer);
        // 读取 --- 读取后的数据会进入废弃字节,打标记可重复度
        System.out.println(buffer.readByte());
        log(buffer);
        //打标记，可重复读
        buffer.markReaderIndex();
        System.out.println(buffer.readByte());
        log(buffer);
        System.out.println(buffer.readByte());
        log(buffer);
        System.out.println(buffer.readByte());
        log(buffer);
        buffer.resetReaderIndex();
        log(buffer);
    }

    public static void sliceDemo() {
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(10);
        buffer.writeBytes(new byte[]{1, 2, 3, 4});
        byte readByte = buffer.readByte();
        System.out.println(ByteBufUtil.prettyHexDump(buffer));
        // 无参 slice 是从原始 ByteBuf 的 read index 到 write index 之间的内容进行切片
        // 切片后的 max capacity 被固定为这个区间的大小，因此不能追加 write
        ByteBuf slice = buffer.slice();
        System.out.println(ByteBufUtil.prettyHexDump(slice));
        // 如果执行，会报 IndexOutOfBoundsException 异常
        // slice.writeByte(5);
        // 由于是零拷贝，所以修改slice的内容也会导致buffer中的内容修改
        slice.setByte(2,5);
        System.out.println(ByteBufUtil.prettyHexDump(slice));
        System.out.println(ByteBufUtil.prettyHexDump(buffer));
    }

    public static void compositeByteBufDemo() {
        ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer(5);
        buf1.writeBytes(new byte[]{1, 2, 3, 4, 5});
        ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer(5);
        buf2.writeBytes(new byte[]{6, 7, 8, 9, 10});
        System.out.println(ByteBufUtil.prettyHexDump(buf1));
        System.out.println(ByteBufUtil.prettyHexDump(buf2));

        // 创建新的ByteBuf来读取合并2个ByteBuf
        ByteBuf buf3 = ByteBufAllocator.DEFAULT
                .buffer(buf1.readableBytes()+buf2.readableBytes());
        buf3.writeBytes(buf1);
        buf3.writeBytes(buf2);
        System.out.println(ByteBufUtil.prettyHexDump(buf3));

        // CompositeByteBuf来合并两个ByteBuf
        CompositeByteBuf buf4 = ByteBufAllocator.DEFAULT.compositeBuffer();
        // true 表示增加新的 ByteBuf 自动递增 write index, 否则 write index 会始终为 0
        buf4.addComponents(true, buf1, buf2);
        System.out.println(ByteBufUtil.prettyHexDump(buf4));
    }

    public static void unpooledDemo() {
        ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer(5);
        buf1.writeBytes(new byte[]{1, 2, 3, 4, 5});
        ByteBuf buf2 = ByteBufAllocator.DEFAULT.buffer(5);
        buf2.writeBytes(new byte[]{6, 7, 8, 9, 10});

        // 当包装 ByteBuf 个数超过一个时, 底层使用了 CompositeByteBuf
        ByteBuf buf3 = Unpooled.wrappedBuffer(buf1, buf2);
        System.out.println(ByteBufUtil.prettyHexDump(buf3));

        ByteBuf buf4 = Unpooled.wrappedBuffer(new byte[]{1, 2, 3}, new byte[]{4, 5, 6});
        System.out.println(buf4.getClass());
        System.out.println(ByteBufUtil.prettyHexDump(buf4));
    }


    private static void log(ByteBuf buffer) {
        int length = buffer.readableBytes();
        int rows = length / 16 + (length % 15 == 0 ? 0 : 1) + 4;
        StringBuilder buf = new StringBuilder(rows * 80 * 2)
                .append("read index:").append(buffer.readerIndex())
                .append(" write index:").append(buffer.writerIndex())
                .append(" capacity:").append(buffer.capacity())
                .append(NEWLINE);
        appendPrettyHexDump(buf, buffer);
        System.out.println(buf.toString());
    }
}
